//
// Created by LiuYou on 2021/8/20.
//

#ifndef HIGHPERFORMANCELINUXSERVERPROGRAMMING_LINUX2_THREADPOOL_HPP
#define HIGHPERFORMANCELINUXSERVERPROGRAMMING_LINUX2_THREADPOOL_HPP


#include <pthread.h>
//#include <array>
#include <memory>
#include <vector>
#include <list>
#include "Locker.hpp"
#include "Semaphore.hpp"


/** 线程池类, 将它定义为模板是为了代码复用。
 * <p>
 * 模板参数 T 是任务类。*/
template<typename T>
class ThreadPool {
public:
    /** 往请求队列中添加任务。
     * <p>
     * 提供两个接口, 一个是 raw pointer, 一个是智能指针。
     * <p>
     * 不, 因为我的 workQueue中的元素是指针指针类型, 所以在使用的时候使用指针指针的版本。*/
    bool append(T* request) {
        queueLocker.lock();
        if (workQueue.size() > maxRequests) {
            queueLocker.unlock();
            return false;
        }
        workQueue.push_back( request );
        queueLocker.unlock();
        queueStat.post();
        return true;
    }

    __attribute__((unused)) bool append(std::unique_ptr<T> request) {
        queueLocker.lock();
        if (workQueue.size() > maxRequests) {
            queueLocker.unlock();
            return false;
        }
        workQueue.push_back( request );
        queueLocker.unlock();
        queueStat.post();
        return true;
    }

private:
    /** 工作线程, 它不断从工作队列中取出任务并执行之。*/
    static void* worker(void* arg) {
        ThreadPool<T>* pool = (ThreadPool<T>*) arg;
//        ThreadPool* pool = (ThreadPool*) arg;

        pool->run();
        return pool;
    }

    void run() {
        while (!stop) {
            queueStat.wait();
            queueLocker.lock();
            if (workQueue.empty()) {
                queueLocker.unlock();
                continue;
            }
//            std::unique_ptr<T> request = std::move( workQueue.front());
            std::unique_ptr<T> request = workQueue.front();
//            std::unique_ptr<T> request( workQueue.front());

//            auto request = workQueue.front();

//            std::shared_ptr<T> request( workQueue.front());

            workQueue.pop_front();
            queueLocker.unlock();
            if (!request) {
                continue;
            }
            /* 这个要具体的任务类要有一个成员函数/成员方法为 process()。*/
            request.process();
        }
    }

public:
    explicit ThreadPool(int threadNumber = 8, int maxRequests = 10000) :
            threadNumber( threadNumber ), maxRequests( maxRequests ), stop( false ), threads() {
        if ((threadNumber <= 0) || (maxRequests <= 0)) {
            throw std::exception();
        }
        for (int i = 0; i < threadNumber; ++i) {
            threads.push_back( std::make_unique<pthread_t>());
        }

        /* 创建 threadNumber个线程, 并将他们都设置为脱离线程。*/
        for (int i = 0; i < threadNumber; ++i) {
            printf( "创建第 %d 线程。\n", i );
            fflush( stdout );
            if (pthread_create( threads[i].get(), nullptr, worker, this ) != 0) {
                throw std::exception();
            }
            if (pthread_detach( *threads[i] )) {
                throw std::exception();
            }
        }
    }

    ~ThreadPool() {
        stop = true;
    }

private:
    /** 线程池中的线程数。*/
    int threadNumber;

    /** 请求队列中允许的最大请求数。*/
    int maxRequests;

    /** 描述线程池的数组, 其大小为 threadNumber。*/
//    pthread_t* threads;
//    std::array<std::unique_ptr<pthread_t>, threadNumber>
    std::vector<std::unique_ptr<pthread_t>> threads;

    /** 请求队列。*/
    std::list<std::unique_ptr<T>> workQueue;

    /** 保护请求队列的互斥锁。*/
    Locker queueLocker;

    /** 是否有任务需要处理。*/
    Semaphore queueStat;

    /** 是否结束线程。*/
    bool stop;

};


#endif //HIGHPERFORMANCELINUXSERVERPROGRAMMING_LINUX2_THREADPOOL_HPP
